package com.youlu.campus.service.ranking.impl;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.MongoCursor;
import com.youlu.campus.base.community.RankingList;
import com.youlu.campus.base.exception.BusinessException;

import com.youlu.campus.service.ranking.entity.UserActivityPointRanking;
import com.youlu.campus.entity.UserInviteCount;
import com.youlu.campus.entity.UserPO;
import com.youlu.campus.entity.VO.RankingListQueryVO;
import com.youlu.campus.entity.VO.req.RankingListResVO;
import com.youlu.campus.service.base.LockService;
import com.youlu.campus.service.invite.UserInviteCountService;
import com.youlu.campus.service.rank.RankBaseService;
import com.youlu.campus.service.ranking.UserInviteCountRankingService;
import com.youlu.campus.service.visitor.VisitorUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class UserInviteCountRankingServiceImpl implements UserInviteCountRankingService {
    @Autowired
    private LockService lockService;
    @Autowired
    private UserInviteCountService userInviteCountService;
    @Autowired
    private RankBaseService rankBaseService;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private VisitorUserService visitorUserService;
    /**
     * 邀请榜缓存Key
     */
    public String RANK_PRE_KEY = "com.luyou.rank.invite-num.activityId:%s:appId:%s:platform:%s";

    @Override
    public RankingListResVO getUserTaskRanking(RankingListQueryVO req, UserPO userPO) {
        log.info(":>>> 获取用户活动邀请排行榜:{}", JSON.toJSONString(req));
        if (Objects.isNull(req) || StringUtils.isBlank(req.getActivityId())) {
            log.error(":>>> 获取活动邀请排行榜参数错误=");
            throw new BusinessException("获取活动邀请排行榜参数错误");
        }
        req.setUserPO(userPO);
        return getUserInviteRankList(req, userPO);
    }

    @Async
    @Override
    public void updateCount(String userId, String activityId, String appId, String platform, Integer count) {
        log.info(":>>> 开始更新用户:{} 邀请排行榜 activityId:{},{}", userId, activityId, count);
        String key = String.format("com.luyou.updateInviteCount:%s:activityId:%s", userId, activityId);
        boolean lock = lockService.tryLock(key, 60, TimeUnit.SECONDS);
        log.info(":>>> 获取用户:{} 活动:{} 邀请排行榜锁结果:{}", userId, activityId, lock);
        if (!lock) {
            return;
        }
        try {
            UserInviteCount db = userInviteCountService.find(userId, activityId, appId, platform);
            String rediskey = this.getRankKey(activityId, appId, platform);
            if (Objects.isNull(db)) {
                log.info(":>>> 用户:{} 活动:{} 邀请排行榜不存在新建", userId, activityId);
                db = new UserInviteCount();
                db.setActivityId(activityId);
                db.setUserId(userId);
                db.setCount(count);
                db.setActivityId(activityId);
                db.setCreatedTime(new Date());
                db.setAppId(appId);
                db.setPlatform(platform);
                userInviteCountService.create(db);
                rankBaseService.addSingleRank(rediskey, userId, Double.valueOf(count + ""));
                return;
            }
            int oldCount = db.getCount();
            db.setCount(count);
            userInviteCountService.increQ(db);
            rankBaseService.remove(rediskey, userId);
            rankBaseService.addSingleRank(rediskey, userId, Double.valueOf(count + "") + oldCount);
            log.info(":>>> 用户活动邀请排行榜存在更新:{},结果:{}", userId);
        } catch (Exception e) {
            log.error(":>>> 更新用户活动邀请排行榜错误:{}", e);
        } finally {
            lockService.unLock(key);
        }

    }

    @Override
    public boolean updateInviteCount(String userId, String activityId, String appId, String platform, Integer count) {
        log.info(":>>> 开始更新用户:{} 邀请排行榜 activityId:{},{}", userId, activityId, count);
        String key = String.format("com.luyou.updateInviteCount:%s:activityId:%s", userId, activityId);
        try {
            boolean lock = lockService.tryLock(key, 60, TimeUnit.SECONDS);
            log.info(":>>> 获取用户:{} 活动:{} 邀请排行榜锁结果:{}", userId, activityId, lock);
            if (!lock) {
                lockService.unLock(key);
                return false;
            }
            UserInviteCount db = userInviteCountService.find(userId, activityId, appId, platform);
            String rediskey = this.getRankKey(activityId, appId, platform);
            if (Objects.isNull(db)) {
                log.info(":>>> 用户:{} 活动:{} 邀请排行榜不存在新建", userId, activityId);
                db = new UserInviteCount();
                db.setActivityId(activityId);
                db.setUserId(userId);
                db.setCount(count);
                db.setActivityId(activityId);
                db.setCreatedTime(new Date());
                db.setAppId(appId);
                db.setPlatform(platform);
                userInviteCountService.create(db);
                rankBaseService.addSingleRank(rediskey, userId, Double.valueOf(count + ""));
            }else{
                int oldCount = db.getCount();
                db.setCount(count);
                userInviteCountService.increQ(db);
                rankBaseService.remove(rediskey, userId);
                rankBaseService.addSingleRank(rediskey, userId, Double.valueOf(count + "") + oldCount);
            }
            log.info(":>>> 用户活动邀请排行榜存在更新:{},结果:{}", userId);
        } catch (Exception e) {
            log.error(":>>> 更新用户活动邀请排行榜错误:{}", e);
        } finally {
            lockService.unLock(key);
        }
        return true;
    }

    @Override
    public String getRankKey(String activityId, String appId, String platform) {
        return String.format(RANK_PRE_KEY, activityId, appId, platform);
    }

    /**
     * 获取用户积分总榜总榜
     *
     * @param req
     * @param userPO
     * @return
     */
    private RankingListResVO getUserInviteRankList(RankingListQueryVO req, UserPO userPO) {
        RankingListResVO rankingListResVO = new RankingListResVO();
        try {
            if (Objects.isNull(req.getPageSize())) {
                req.setPageSize(10);
            }
            Query query = new Query();
            if (StringUtils.isNotBlank(req.getActivityId())) {
                query.addCriteria(Criteria.where("activityId").is(req.getActivityId()));
                log.info(":>>> 活动ID:{},任务ID:{}", req.getActivityId(), req.getTaskId());
            }
//            query.with(new Sort(Sort.Direction.DESC, "count"));
            Sort sort=Sort.by(Sort.Direction.DESC, "count");
            query.with(sort);
            // TODO：需要添加
//            query.with(new Sort(Sort.Direction.ASC, "createdTime"));
            query.limit(req.getPageSize());
            Long count = mongoTemplate.getCollection(mongoTemplate.getCollectionName(UserInviteCount.class)).countDocuments(query.getQueryObject());
            Integer totalPages = 0;
            if (count.intValue() == 0) {
                totalPages = 0;
            } else {
                if (count.intValue() % req.getPageSize() == 0) {
                    totalPages = count.intValue() / req.getPageSize();
                } else {
                    totalPages = count.intValue() / req.getPageSize() + 1;
                }
            }
            log.info(":>>> 用户积分排行榜数量:{},总页数:{},每页大小:{},当前页:{}", count, totalPages, req.getPageSize(), req.getPage());
            List<UserActivityPointRanking> rankings = null;
            if (totalPages < req.getPage()) {
                rankings = new ArrayList<>();
                log.info(":>>> 排行榜总页数:{} 是最后一页:{}", totalPages, req.getPage());

            } else {
                query.skip((req.getPage() - 1) * req.getPageSize());
                MongoCursor iterable = mongoTemplate.getCollection(mongoTemplate.getCollectionName(UserInviteCount.class)).find(query.getQueryObject()).limit(req.getPageSize()).skip((req.getPage() - 1) * req.getPageSize()).
                        noCursorTimeout(true).sort(query.getSortObject()).batchSize(req.getPageSize()).iterator();
                if (Objects.isNull(rankings)) {
                    rankings = new ArrayList<>();
                }
                Document o = null;
                UserActivityPointRanking r = null;
                while (iterable.hasNext()) {
                    o = (Document) iterable.next();
                    if (Objects.nonNull(o)) {
                        r = new UserActivityPointRanking();
//                        r.setId(o.getObjectId("id").toString());
                        r.setName(o.getString("nickName"));
                        r.setImageUrl(o.getString("imageUrl"));
                        r.setQuantity(Double.valueOf(o.getInteger("count") + ""));
                        r.setUserId(o.getString("userId"));
                        rankings.add(r);
                    }
                }

            }
            List<RankingList> rankingLists = new ArrayList<>();
            boolean in = false;
            int orderNN = (req.getPage() - 1) * req.getPageSize();
            int order = 1;
            List<String> userIds = new ArrayList<>();
            for (UserActivityPointRanking d : rankings) {
                if (StringUtils.isNotBlank(d.getUserId())) {
                    userIds.add(d.getUserId());
                }
            }
            HashMap<String, UserPO> userPOHashMap = visitorUserService.getByUserIdsAndPlatform(userIds, req.getPlatform(),req.getAppId());
            for (UserActivityPointRanking d : rankings) {
                if (req.getUserId().equals(d.getUserId())) {
                    in = true;
                }
                RankingList rankingList = new RankingList();
                UserPO userPO1 = userPOHashMap.get(d.getUserId());
                if (Objects.nonNull(userPO1)) {
                    rankingList.setImageUrl(userPO1.getAvatarUrl());
                    rankingList.setName(userPO1.getNickName());
                }
                if (Objects.nonNull(d.getQuantity())) {
                    BigDecimal b = new BigDecimal(d.getQuantity());
                    Double q = b.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
                    rankingList.setQuantity(q);
                }
                rankingList.setOrderNo(orderNN + order);
                if (Objects.nonNull(d.getQuantity())) {
                    rankingList.setRankingValue("已邀请" + d.getQuantity().intValue() + "人");
                }
                rankingLists.add(rankingList);
                order++;
            }
            rankingListResVO.setDatas(rankingLists);
            rankingListResVO.setInRanking(in);

            //redis取排名(redis更新有问题暂时废弃)
//            Long uO = rankBaseService.getSingleRankOrder(this.getRankKey(req.getActivityId(), req.getAppId(), req.getPlatform()), userPO.getId());
//            if (Objects.isNull(uO)) {
//                uO = 0L;
//            }

//            Double q = rankBaseService.getSingleRankScore(this.getRankKey(req.getActivityId(), req.getAppId(), req.getPlatform()), userPO.getId());
//            if (Objects.isNull(q)) {
//                q = 0D;
//            }

            //数据库取排名
            Long uO = 0L;
            Double q = 0D;
            UserInviteCount userInviteCount = mongoTemplate.findOne(new Query().addCriteria(Criteria.where("activityId").is(req.getActivityId()).and("userId").is(userPO.getId())), UserInviteCount.class);
            if (Objects.nonNull(userInviteCount)) {
                //相同分值按第一次邀请成功时间排序
                long gtCountRank = mongoTemplate.count(new Query().addCriteria(Criteria.where("activityId").is(req.getActivityId()).and("count").gt(userInviteCount.getCount())), UserInviteCount.class);
                long eqCountRank = mongoTemplate.count(new Query().addCriteria(Criteria.where("activityId").is(req.getActivityId()).and("count").is(userInviteCount.getCount()).and("createdTime").lte(userInviteCount.getCreatedTime())), UserInviteCount.class);
                uO = gtCountRank + eqCountRank;
                q = Double.valueOf("" + userInviteCount.getCount());
            }

            log.info(":>>> 活动:{},用户:{},名次:{},邀请人数:{}", req.getActivityId(), req.getUserId(), uO, q);
            rankingListResVO.setOrderNo(uO.intValue());
            rankingListResVO.setQuantity(q);
            rankingListResVO.setRankValue("已邀请" + q.intValue() + "人");
            rankingListResVO.setInRanking(in);
            rankingListResVO.setPage(req.getPage());
            rankingListResVO.setImageUrl(userPO.getAvatarUrl());
            rankingListResVO.setName(userPO.getNickName());
            rankingListResVO.setPageSize(req.getPageSize());
            rankingListResVO.setTotalPages(count.intValue() / req.getPageSize() + 1);
        } catch (Exception e) {
            log.error(":>>> 获取邀请人数排行榜错误:{}", e);
        }
        return rankingListResVO;
    }
}
